package com.beiding.my.bemapping;

import com.beiding.my.common.BeRepository;
import com.beiding.my.dtmapping.DtFieldMapper;
import com.beiding.my.dtmapping.DtTypeMapper;
import com.beiding.my.dtmapping.DtTypeMapperHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class BeTypeMapperHolder {


    private List<BeRepository> beRepositories;

    private DtTypeMapperHolder dtTypeMapperHolder;

    public BeTypeMapperHolder(@Autowired(required = false) List<BeRepository> boRepositories, DtTypeMapperHolder beTypeMapperHolder) {
        this.beRepositories = boRepositories;
        this.dtTypeMapperHolder = beTypeMapperHolder;
        try {
            init();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private Map<Class, BeTypeMapper> typeBoTypeMapperMap = new HashMap<>();
    private Map<String, BeTypeMapper> nameBoTypeMapperMap = new HashMap<>();

    public <T> BeTypeMapper<T> getBoTypeMapper(Class<T> type) {
        return typeBoTypeMapperMap.get(type);
    }

    public BeTypeMapper getBoTypeMapper(String name) {
        return nameBoTypeMapperMap.get(name);
    }


    private void init() throws Exception {

        if (beRepositories != null)
            for (BeRepository repository : beRepositories) {
                BeTypeMapper beTypeMapper = new BeTypeMapper();
                Class<? extends BeRepository> boRepositoryType = repository.getClass();

                String simpleName = boRepositoryType.getSimpleName();

                String boTypeName = simpleName.substring(0, simpleName.length() - 10);
                Class boType = Class.forName(boRepositoryType.getPackage().getName() + "." + boTypeName);

                beTypeMapper.type = boType;
                beTypeMapper.name = boTypeName;

                //获取到be实体的类型
                DtTypeMapper dtTypeMapper = dtTypeMapperHolder.getMapper(boTypeName + "Dt");
                beTypeMapper.dtTypeMapper = dtTypeMapper;
                //带有泛型的就必须强转
                for (DtFieldMapper field : (List<DtFieldMapper>) dtTypeMapper.getFields()) {
                    BeFieldMapper boFieldMapper = new BeFieldMapper();
                    boFieldMapper.dtTypeMapper = dtTypeMapper;
                    boFieldMapper.name = field.getName();
                    boFieldMapper.beFiled = boType.getDeclaredField("_dt");
                    boFieldMapper.beFiled.setAccessible(true);
                    beTypeMapper.addAttributeMapper(boFieldMapper);
                }

                typeBoTypeMapperMap.put(boType, beTypeMapper);
                nameBoTypeMapperMap.put(boTypeName, beTypeMapper);
            }

        for (BeTypeMapper boTypeMapper : typeBoTypeMapperMap.values()) {
            Class boType = boTypeMapper.type;
            for (Field field : boType.getDeclaredFields()) {
                String name = field.getName();
                if (name.startsWith("_quote_")) {
                    name = name.substring(7);
                    field.setAccessible(true);

                    //判断引用类型
                    Class<?> type = field.getType();

                    if (type == List.class) {

                        Type genericType = field.getGenericType();

                        if (genericType == null) {
                            throw new RuntimeException(field + "无法确定泛型类型");
                        }

                        if (genericType instanceof ParameterizedType) {
                            ParameterizedType parameterizedType = (ParameterizedType) genericType;
                            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                            if (actualTypeArguments.length != 1) {
                                throw new RuntimeException(field + "无法确定泛型类型");
                            }

                            Class t = (Class) actualTypeArguments[0];

                            BeListQuoteMapper beListQuoteMapper = new BeListQuoteMapper();

                            beListQuoteMapper.name = name;
                            beListQuoteMapper.quoteFiled = field;
                            beListQuoteMapper.realBoTypeMapper = typeBoTypeMapperMap.get(t);
                            boTypeMapper.addAttributeMapper(beListQuoteMapper);

                        } else {
                            throw new RuntimeException(field + "无法确定泛型类型");
                        }

                    } else {
                        BeQuoteMapper boQuoteMapper = new BeQuoteMapper();
                        boQuoteMapper.name = name;
                        boQuoteMapper.quoteFiled = field;
                        boQuoteMapper.realBoTypeMapper = typeBoTypeMapperMap.get(type);
                        boTypeMapper.addAttributeMapper(boQuoteMapper);
                    }
                }
            }
        }


    }
}
